﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Button = System.Windows.Controls.Button;
using Clipboard = System.Windows.Clipboard;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using Label = System.Windows.Controls.Label;
using System.Media;

namespace Brite.Controls
{
    public partial class MessageBoxEx
    {
        #region Private Data

        private const string OptionCheckDefaultMessage = "Don't show this message again";

        private MessageBoxExInfo m_info;
        private string m_result;

        #endregion

        #region Constructors

        private MessageBoxEx(MessageBoxExInfo i_info)
        {
            InitializeComponent();
            m_info = i_info;
            initialize();
        }

        private void initialize()
        {
            Title = m_info.Title;
            Text = m_info.Text;

            if (m_info.Owner != null)
            {
                Owner = m_info.Owner;
            }
            else if (m_info.OwnerForm != null)
            {
                var msgBoxHelper = new WindowInteropHelper(this);
                msgBoxHelper.Owner = m_info.OwnerForm.Handle;
            }
            else
            {
                WindowStartupLocation = WindowStartupLocation.CenterScreen;
            }

            setIconImage(m_info.Icon ?? GetImageSource(m_info.IconUri));

            createButtons(m_info.Buttons);

            if (m_info.UseOptionCheck)
                setOptionCheck(m_info.OptionCheckValue, m_info.OptionCheckText);
        }

        #endregion

        #region Public Members

        public static string Show(MessageBoxExInfo i_info)
        {
            return Create(i_info).display();
        }
        
        public static string Show(string i_text, string i_title)
        {
            return Create(i_text, i_title).display();
        }

        public static string Show(Window i_owner, string i_text, string i_title)
        {
            return Create(i_owner, i_text, i_title).display();
        }

        public static string Show(Form i_owner, string i_text, string i_title)
        {
            return Create(i_owner, i_text, i_title).display();
        }

        public static string Show(string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons)
        {
            return Create(i_text, i_title, i_buttons).display();
        }

        public static string Show(Window i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons)
        {
            return Create(i_owner, i_text, i_title, i_buttons).display();
        }

        public static string Show(Form i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons)
        {
            return Create(i_owner, i_text, i_title, i_buttons).display();
        }

        public static string Show(string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, string i_iconPackUri)
        {
            return Create(i_text, i_title, i_buttons, i_iconPackUri).display();
        }

        public static string Show(Window i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, string i_iconPackUri)
        {
            return Create(i_owner, i_text, i_title, i_buttons, i_iconPackUri).display();
        }

        public static string Show(Form i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, string i_iconPackUri)
        {
            return Create(i_owner, i_text, i_title, i_buttons, i_iconPackUri).display();
        }
        
        public static string Show(string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, ImageSource i_icon)
        {
            return Create(i_text, i_title, i_buttons, i_icon).display();
        }

        public static string Show(Window i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, ImageSource i_icon)
        {
            return Create(i_owner, i_text, i_title, i_buttons, i_icon).display();
        }

        public static string Show(Form i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, ImageSource i_icon)
        {
            return Create(i_owner, i_text, i_title, i_buttons, i_icon).display();
        }

        public void CloseWithResult(string i_result)
        {
            m_result = i_result;
            Close();
        }

        #endregion

        #region Overrides

        protected override void OnSourceInitialized(EventArgs i_e)
        {
            base.OnSourceInitialized(i_e);
            this.RemoveIcon();
        }

        protected override void OnKeyDown(KeyEventArgs i_e)
        {
            if (!i_e.Handled)
            {
                if (Keyboard.Modifiers == ModifierKeys.None && i_e.Key == Key.Escape)
                {
                    CloseWithResult(getEscapeButton().Result);
                    i_e.Handled = true;
                }

                if (Keyboard.Modifiers == ModifierKeys.Control && i_e.Key == Key.C)
                {
                    Clipboard.SetText(getTextToCopy());
                    i_e.Handled = true;
                }
            }

            base.OnKeyDown(i_e);
        }

        #endregion

        #region Event Handlers

        private void onButtonClick(object i_sender, RoutedEventArgs i_e)
        {
            var button = (Button)i_sender;
            var info = (MessageBoxExButton)button.Tag;
            if (info.Callback != null)
                info.Callback();
            else
                CloseWithResult(info.Result);
        }

        #endregion

        #region Private Implementation

        private static MessageBoxEx Create(string i_text, string i_title)
        {
            return Create((Window)null, i_text, i_title, null, (ImageSource)null);
        }

        private static MessageBoxEx Create(Window i_owner, string i_text, string i_title)
        {
            return Create(i_owner, i_text, i_title, null, (ImageSource)null);
        }

        private static MessageBoxEx Create(Form i_owner, string i_text, string i_title)
        {
            return Create(i_owner, i_text, i_title, null, (ImageSource)null);
        }

        private static MessageBoxEx Create(string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons)
        {
            return Create((Window)null, i_text, i_title, i_buttons, (ImageSource)null);
        }

        private static MessageBoxEx Create(Window i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons)
        {
            return Create(i_owner, i_text, i_title, i_buttons, (ImageSource)null);
        }

        private static MessageBoxEx Create(Form i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons)
        {
            return Create(i_owner, i_text, i_title, i_buttons, (ImageSource)null);
        }

        private static MessageBoxEx Create(string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, string i_iconPackUri)
        {
            return Create((Window)null, i_text, i_title, i_buttons, GetImageSource(i_iconPackUri));
        }

        private static MessageBoxEx Create(Window i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, string i_iconPackUri)
        {
            return Create(i_owner, i_text, i_title, i_buttons, GetImageSource(i_iconPackUri));
        }

        private static MessageBoxEx Create(Form i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, string i_iconPackUri)
        {
            return Create(i_owner, i_text, i_title, i_buttons, GetImageSource(i_iconPackUri));
        }

        private static MessageBoxEx Create(string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, ImageSource i_icon)
        {
            var info = new MessageBoxExInfo
            {
                Title = i_title,
                Text = i_text,
                Icon = i_icon,
                Buttons = i_buttons,
            };
            return Create(info);
        }

        private static MessageBoxEx Create(Window i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, ImageSource i_icon)
        {
            var info = new MessageBoxExInfo
            {
                Owner = i_owner,
                Title = i_title,
                Text = i_text,
                Icon = i_icon,
                Buttons = i_buttons,
            };
            return Create(info);
        }

        private static MessageBoxEx Create(Form i_owner, string i_text, string i_title, IEnumerable<MessageBoxExButton> i_buttons, ImageSource i_icon)
        {
            var info = new MessageBoxExInfo
            {
                OwnerForm = i_owner,
                Title = i_title,
                Text = i_text,
                Icon = i_icon,
                Buttons = i_buttons,
            };
            return Create(info);
        }

        private static MessageBoxEx Create(MessageBoxExInfo i_info)
        {
            return new MessageBoxEx(i_info);
        }

        private void createButtons(IEnumerable<MessageBoxExButton> i_buttons)
        {
            if (i_buttons == null || i_buttons.Count() == 0)
            {
                i_buttons = MessageBoxExButtons.OK;
            }

            foreach (var buttonInfo in i_buttons)
            {
                var button = new Button
                {
                    MinWidth = 75,
                    Height = 23,
                    Margin = new Thickness(6, 0, 6, 0),
                    Padding = new Thickness(0)
                };

                var label = new Label
                {
                    Margin = new Thickness(3, 0, 3, 0),
                    Padding = new Thickness(0),
                    VerticalContentAlignment = VerticalAlignment.Center,
                    Content = buttonInfo.Caption,
                    FontWeight = buttonInfo.Strong ? FontWeights.Bold : FontWeights.Regular,
                };

                button.Content = label;

                button.IsDefault = buttonInfo.Default == true;
                button.IsCancel = buttonInfo.Default == false;
                button.Visibility = buttonInfo.Visible ? Visibility.Visible : Visibility.Collapsed;

                buttonsPanel.Children.Add(button);

                button.Click += onButtonClick;
                button.Tag = buttonInfo;
            }
        }

        private string display()
        {
            playSound();
            ShowDialog();
            m_info.OptionCheckValue = optionCheck.IsChecked;
            return m_result ?? (m_result = getEscapeButton().Result);
        }

        private void playSound()
        {
            SystemSound sound = null;

            if (image.Source == MessageBoxExIcons.Asterisk ||
                image.Source == MessageBoxExIcons.Information)
            {
                sound = SystemSounds.Asterisk;
            }

            if (image.Source == MessageBoxExIcons.Hand ||
                image.Source == MessageBoxExIcons.Error)
            {
                sound = SystemSounds.Hand;
            }

            if (image.Source == MessageBoxExIcons.Exclamation ||
                image.Source == MessageBoxExIcons.Warning)
            {
                sound = SystemSounds.Exclamation;
            }

            if (image.Source == MessageBoxExIcons.Question)
            {
                sound = SystemSounds.Question;
            }

            if (image.Source == MessageBoxExIcons.Shield ||
                image.Source == MessageBoxExIcons.WinLogo ||
                image.Source == MessageBoxExIcons.Application)
            {
                sound = SystemSounds.Beep;
            }

            if (sound != null) sound.Play();
        }

        private MessageBoxExButton getEscapeButton()
        {
            var children = new UIElement[buttonsPanel.Children.Count];
            buttonsPanel.Children.CopyTo(children, 0);
            var buttons = from uiElement in children
                          where uiElement is Button
                          select (MessageBoxExButton)((Button)uiElement).Tag;

            MessageBoxExButton escapeButton =
               (buttons.FirstOrDefault(i_button => i_button.Default == false) ??
                buttons.FirstOrDefault(i_button => i_button.Default == null)) ??
                buttons.FirstOrDefault(i_button => i_button.Default == true);

            return escapeButton;
        }

        private void setIconImage(ImageSource i_iconImage)
        {
            image.Source = i_iconImage;
            image.Visibility = i_iconImage != null ? Visibility.Visible : Visibility.Collapsed;
        }

        private string Text
        {
            get { return message.Text; }
            set { message.Text = value; }
        }

        private void setOptionCheck(bool? i_value, string i_text)
        {
            optionCheck.IsChecked = i_value;
            optionCheck.Visibility = Visibility.Visible;
            optionText.Content = i_text ?? OptionCheckDefaultMessage;
        }

        private string getTextToCopy()
        {
            var sb = new StringBuilder();
            sb.AppendLine("---------------------------");
            sb.AppendLine(Title);
            sb.AppendLine("---------------------------");
            sb.AppendLine(Text);
            sb.AppendLine("---------------------------");
            foreach (Button button in buttonsPanel.Children)
            {
                var buttonInfo = ((MessageBoxExButton)button.Tag);
                if (!buttonInfo.Visible) continue;
                sb.AppendFormat("[{0}]   ", buttonInfo.Caption.Replace("_", ""));
            }
            sb.AppendLine();
            sb.AppendLine("---------------------------");

            return sb.ToString();
        }

        #endregion

        #region Utils

        public static ImageSource GetImageSource(string i_iconPackUri)
        {
            try
            {
                return new BitmapImage(new Uri(i_iconPackUri, UriKind.RelativeOrAbsolute));
            }
            catch
            {
                return null;
            }
        }

        #endregion
    }
}
